package test;

import java.util.List;

import lucava.metamodel.dot.DotGraph;
import lucava.metamodel.dot.visitor.DotFileGenerator;
import lucava.metamodel.java.Attribute;
import lucava.metamodel.java.MetaClasse;
import lucava.metamodel.java.MetaInterface;
import lucava.metamodel.java.MetaModel;
import lucava.metamodel.java.MetaPackage;
import lucava.metamodel.java.type.MetaType;
import lucava.metamodel.java.visitor.DotMetaModelGenerator;
import lucava.metamodel.java.visitor.JavaFileGenerator;
import lucava.util.FileBuffer;
import lucava.util.FileBufferWriter;
import lucava.util.GraphVizGenerator;

public class JavaGeneratorTester {

	public static void main(String[] args) {
		testGenerators2();
	}

	public static void testGenerators1() {

		MetaModel dotMetaModel = getDotMetaModel();

		// Génération des classes JAVA associés au MetaModel de DOT.
		JavaFileGenerator javaFileGenerator = new JavaFileGenerator();
		dotMetaModel.accept(javaFileGenerator);

		// Ecriture des fichiers générés
		List<FileBuffer> javaFiles = javaFileGenerator.getGeneratedFiles();
		FileBufferWriter.generateFileFor(javaFiles);

		// Génération du MetaModel DOT depuis le MetaModel Java de DOT
		DotMetaModelGenerator dotGenerator = new DotMetaModelGenerator();
		dotMetaModel.accept(dotGenerator);

		DotGraph dotModelgraph = dotGenerator.getGeneratedGraph();

		// Transformation en fichier DOT depuis le MetaModel DOT
		DotFileGenerator dotFileGenerator = new DotFileGenerator();
		dotModelgraph.accept(dotFileGenerator);

		// Ecriture du fichier généré
		FileBuffer dotFile = dotFileGenerator.getGeneratedFile();
		FileBufferWriter.generateFileFor(dotFile);

		// Génération du graphe correspondant au .DOT
		GraphVizGenerator.generatePNGFromFile(dotMetaModel.getName() + ".dot","data/test/GeneratedGraph2.png");

		// Sans passer par le fichier :
		// GraphVizGenerator.generatePNGFromString(dotFile.getContent() +
		// ".dot");
	}

	public static void testGenerators2() {

		MetaModel aMetaModel = getAJavaMetaModel();

		// Génération du MetaModel DOT depuis le MetaModel Java de DOT
		DotMetaModelGenerator dotGenerator = new DotMetaModelGenerator();
		aMetaModel.accept(dotGenerator);

		DotGraph dotModelgraph = dotGenerator.getGeneratedGraph();

		// Transformation en fichier DOT depuis le MetaModel DOT
		DotFileGenerator dotFileGenerator = new DotFileGenerator();
		dotModelgraph.accept(dotFileGenerator);

		// Ecriture du fichier généré
		FileBuffer dotFile = dotFileGenerator.getGeneratedFile();
		FileBufferWriter.generateFileFor(dotFile);

		// Génération du graphe correspondant au .DOT
		GraphVizGenerator.generatePNGFromFile(aMetaModel.getName() + ".dot","data/test/GeneratedGraph3.png");
	}

	public static MetaModel getDotMetaModel() {
		MetaPackage dotMetaModelPackage = new MetaPackage("dotMetaModel");

		MetaModel dotMetaModel = new MetaModel("DotMetaModel");

		MetaInterface modelVisitor = new MetaInterface("IDotMetaModelVisitor");
		modelVisitor.setPackage(dotMetaModelPackage + ".visitor");
		dotMetaModel.setVisitableBy(modelVisitor);

		MetaClasse propertyClass = new MetaClasse("DotProperty");
		propertyClass.addAttribute(new MetaClasse("String"), "propertyValue",
				"1");
		propertyClass.setPackage(dotMetaModelPackage);

		MetaClasse labelClass = new MetaClasse("DotLabel");
		labelClass.setPackage(dotMetaModelPackage);
		labelClass.addAttribute(new MetaClasse("String"), "labelValue", "1");

		MetaClasse nodeClass = new MetaClasse("DotNode");
		nodeClass.setPackage(dotMetaModelPackage);
		nodeClass.addAttribute(new MetaClasse("String"), "name", "1");
		nodeClass.addAttribute(labelClass, "nodeLabel", "1");

		MetaClasse graphClass = new MetaClasse("DotGraph");
		MetaClasse subgraphClass = new MetaClasse("DotSubgraph");

		MetaClasse associationClass = new MetaClasse("DotAssociation");
		associationClass.setPackage(dotMetaModelPackage);
		associationClass.addAttribute(nodeClass, "fromNode", "1");
		associationClass.addAttribute(nodeClass, "toNode", "1");
		associationClass.addAttribute(propertyClass, "properties", "*");

		graphClass.setPackage(dotMetaModelPackage);
		graphClass.addAttribute(new MetaClasse("String"), "name", "1");
		graphClass.addAttribute(nodeClass, "nodes", "*");
		graphClass.addAttribute(subgraphClass, "subGraphs", "*");
		graphClass.addAttribute(labelClass, "graphLabel", "1");
		graphClass.addAttribute(associationClass, "associations", "*");

		subgraphClass.setPackage(dotMetaModelPackage);
		subgraphClass.setExtends(graphClass);

		dotMetaModel.add(propertyClass);
		dotMetaModel.add(subgraphClass);
		dotMetaModel.add(labelClass);
		dotMetaModel.add(nodeClass);
		dotMetaModel.add(graphClass);
		dotMetaModel.add(associationClass);

		return dotMetaModel;
	}

	public static MetaModel getAJavaMetaModel() {
		MetaPackage javaMetaModelPackage = new MetaPackage("javaPackage");

		MetaModel javaMetaModel = new MetaModel("SampleJavaMetaModel");

		MetaInterface modelVisitor = new MetaInterface(
				"ISampleJavaMetaModelVisitor");
		modelVisitor.setPackage(javaMetaModelPackage + ".visitor");
		javaMetaModel.setVisitableBy(modelVisitor);

		MetaInterface supInterface1 = new MetaInterface("SupInterface1");
		supInterface1.setPackage(javaMetaModelPackage);

		MetaInterface supInterface2 = new MetaInterface("SupInterface2");
		supInterface2.setPackage(javaMetaModelPackage);

		MetaInterface interface1 = new MetaInterface("Interface1");
		interface1.setPackage(javaMetaModelPackage);
		interface1.addExtends(supInterface1);
		interface1.addExtends(supInterface2);

		MetaClasse supClass = new MetaClasse("SupClasse");
		supClass.setPackage(javaMetaModelPackage);
		supClass.setAbstract(true);

		MetaClasse class1 = new MetaClasse("Classe");
		class1.setPackage(javaMetaModelPackage);
		class1.setExtends(supClass);
		class1.addImplements(interface1);

		MetaClasse class2 = new MetaClasse("ClasseInt");
		class2.setPackage(javaMetaModelPackage);
		class2.addImplements(supInterface2);

		Attribute cl1Attr1 = new Attribute(class2, "classe2Aggreg");
		cl1Attr1.setProperty("association", "aggregation");
		class1.addAttribute(cl1Attr1);

		Attribute cl1Attr2 = new Attribute(class2, "classe2Compo");
		cl1Attr2.setProperty("association", "composition");
		class1.addAttribute(cl1Attr2);

		Attribute cl1Attr3 = new Attribute(class2, "classe2Simple");
		cl1Attr3.setProperty("association", "simple");
		class1.addAttribute(cl1Attr3);

		class1.addAttribute(new MetaType("int"), "unInt");

		javaMetaModel.add(supInterface1);
		javaMetaModel.add(supInterface2);
		javaMetaModel.add(interface1);
		javaMetaModel.add(supClass);
		javaMetaModel.add(class1);
		javaMetaModel.add(class2);

		return javaMetaModel;
	}
}
